package com.smileus.integration.caller;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import com.smileus.common.OneResult;
import com.smileus.common.OneTask;
import com.smileus.integration.caller.impl.CxfBatchCaller;
import com.smileus.util.JSONUtil;

public class GeneralBatchCaller {
	private GeneralBatchCaller() {
	}

	// key是URL
	protected static Map<String, BlockingQueue<OneTask>> URL_QUEUE_MAP = new ConcurrentHashMap<String, BlockingQueue<OneTask>>();
	// 对应各个线程请求结果
	protected static Map<Long, String> ONE_TASK_RESULT_MAP = new ConcurrentHashMap<Long, String>();
	private static Map<String, BatchCaller> BATCH_HANDLER_MAP = new ConcurrentHashMap<String, BatchCaller>() {
		private static final long serialVersionUID = 1L;
		{
			put("cxf", new CxfBatchCaller());
		}
	};
	/**
	 * 获取每次请求结果 注意：一次性消费，获取之后立即删除
	 */
	public static String getOneTaskResult(long seq) {
		while (true) {// 发送异常，值没有放进Map 如何处理？
			if (ONE_TASK_RESULT_MAP.containsKey(seq)) {
				return ONE_TASK_RESULT_MAP.remove(seq);// 拿到之后 立马清理掉;
			}
			/**
			 * TODO:确定休息多长时间较好？ CPU分配的最小时间片断为2毫秒, 如果值还没放进MAP，那么就先等待n个时间片吧
			 * 测试发现，正常情况下一次网络连接耗时一般在20毫秒-180毫秒之间，这一段时间可以留给其他线程去执行任务。
			 */
			try {
				Thread.sleep(20);// 单位是微妙，1000毫秒=1微妙
			} catch (InterruptedException e) {
				return "[result={result:'null',success:'false',desc:'发送异常.'}, seq=" + seq + "}]";
			}
		}
	}

	private static final Map<String, ScheduledExecutorService> callExecutorMap = new HashMap<String, ScheduledExecutorService>();
	public static void putTask(final String url, final OneTask oneTask) {
		if (URL_QUEUE_MAP.containsKey(url)) {
			URL_QUEUE_MAP.get(url).add(oneTask);
		} else {
			BlockingQueue<OneTask> queue = new LinkedBlockingQueue<OneTask>();
			queue.add(oneTask);
			URL_QUEUE_MAP.put(url, queue);
			ScheduledExecutorService curtExecutor = Executors.newScheduledThreadPool(1);
			callExecutorMap.put(url, curtExecutor);
			// final String name="taskThread:" + seq.getAndIncrement();
			final Runnable taskThread = new Runnable() {
				public void run() {
					// 从队列中取要执行的单个任务，组装成批量任务
					final List<OneTask> tasks = new ArrayList<OneTask>();
					URL_QUEUE_MAP.get(url).drainTo(tasks);
					if (tasks.size() != 0) {
						long start = System.currentTimeMillis();
						String result = BATCH_HANDLER_MAP.get(oneTask.getCallInfo().getServiceType()).batchCall(url, tasks);
						List<OneResult> resultList = JSONUtil.toList(result, OneResult.class);
						if (resultList != null && resultList.size() != 0) {
							for (OneResult oneResult : resultList) {
								ONE_TASK_RESULT_MAP.put(oneResult.getSeq(), oneResult.getResult());
							}
						}
						System.out.println("任务数："+ tasks.size()+",耗时:"+ (System.currentTimeMillis() - start));
					}
				}
			};
			// 40微妙后运行，并每隔500微妙秒运行一次
			curtExecutor.scheduleAtFixedRate(taskThread, 10, 24, TimeUnit.MICROSECONDS);
		}
	}
}
